"""
版本状态自动流转服务
负责检查版本状态流转条件并自动执行流转
"""
from typing import Optional, Dict
from datetime import datetime
from motor.motor_asyncio import AsyncIOMotorDatabase  # pyright: ignore[reportMissingImports]
from bson import ObjectId  # pyright: ignore[reportMissingImports]
import logging
from pymongo.errors import OperationFailure  # pyright: ignore[reportMissingImports]

from app.services.version_completion_service import VersionCompletionService
from app.services.version_transition_rules import VersionTransitionRules, TransitionRule

logger = logging.getLogger(__name__)


class VersionAutoTransitionService:
    """版本状态自动流转服务"""
    
    def __init__(self, db: AsyncIOMotorDatabase):
        self.db = db
        self.completion_service = VersionCompletionService(db)
    
    async def check_and_transition(
        self,
        version_id: ObjectId,
        trigger_source: Optional[str] = None
    ) -> Optional[Dict]:
        """
        检查版本是否满足流转条件，如果满足则自动流转
        
        Args:
            version_id: 版本ID
            trigger_source: 触发来源（task/defect/requirement/test/manual）
        
        Returns:
            流转结果信息，如果未流转则返回None
        """
        try:
            # 1. 获取版本信息
            version = await self.db.versions.find_one({"_id": version_id})
            if not version:
                logger.warning(f"版本不存在: {version_id}")
                return None
            
            # 从状态管理系统获取默认状态
            from app.utils.state_utils import get_default_state_code
            default_status = await get_default_state_code(self.db, "version")
            current_status = version.get("status") or default_status or ""
            
            # 2. 获取自动流转规则
            rules = VersionTransitionRules.get_auto_trigger_rules(current_status)
            
            if not rules:
                # 当前状态没有自动流转规则
                return None
            
            # 3. 根据状态计算指标
            # 从状态管理系统获取草稿和规划状态
            from app.utils.state_utils import get_state_code_by_name_keywords
            draft_code = await get_state_code_by_name_keywords(self.db, "version", ["草稿", "draft"])
            planning_code = await get_state_code_by_name_keywords(self.db, "version", ["规划中", "planning"])
            early_statuses = [s for s in [draft_code, planning_code] if s]
            if current_status in early_statuses:
                # 早期状态使用准备度指标
                readiness_data = await self.completion_service.calculate_readiness_metrics(
                    version_id, version
                )
                completion_data = {}
            else:
                # 后期状态使用完成度指标
                completion_data = await self.completion_service.calculate_completion_rate(version_id)
                readiness_data = {}
            
            # 4. 检查每个规则的条件
            for rule in rules:
                is_met, unmet_conditions = await VersionTransitionRules.check_rule_conditions(
                    rule, completion_data, readiness_data, version, self.db
                )
                
                if is_met:
                    # 条件满足，执行流转
                    logger.info(
                        f"版本 {version_id} 满足自动流转条件: {current_status} -> {rule.to_status}"
                    )
                    return await self._execute_transition(
                        version_id, current_status, rule.to_status,
                        completion_data or readiness_data, trigger_source
                    )
            
            return None
            
        except Exception as e:
            logger.error(f"检查版本状态流转失败: {str(e)}", exc_info=True)
            return None
    
    async def _execute_transition(
        self,
        version_id: ObjectId,
        from_status: str,
        to_status: str,
        data: Dict,
        trigger_source: Optional[str],
        *,
        transition_type: str = "auto",
        operator_id: Optional[ObjectId] = None,
        reason: Optional[str] = None,
        comment: Optional[str] = None
    ) -> Dict:
        """执行状态流转"""
        async def _apply_changes(session=None) -> None:
            update_data = {
                "status": to_status,
                "updated_at": datetime.utcnow()
            }
            
            # 如果转换到已发布状态，更新实际发布时间 - 使用动态状态判断
            from app.utils.state_utils import get_state_code_by_name_keywords
            released_status_code = await get_state_code_by_name_keywords(self.db, "version", ["已发布", "发布", "released"])
            if released_status_code and to_status == released_status_code and not data.get("actual_release_date"):
                update_data["actual_release_date"] = datetime.utcnow()
            
            update_kwargs = {
                "filter": {"_id": version_id},
                "update": {"$set": update_data}
            }
            if session is not None:
                update_kwargs["session"] = session
            
            await self.db.versions.update_one(**update_kwargs)
            
            # 记录流转历史（可选）
            history_doc = {
                "version_id": version_id,
                "from_status": from_status,
                "to_status": to_status,
                "transition_type": transition_type,
                "trigger_source": trigger_source or "system",
                "operator_id": operator_id,
                "reason": reason,
                "comment": comment,
                "completion_data": data,
                "created_at": datetime.utcnow()
            }
            try:
                insert_kwargs = {"document": history_doc}
                if session is not None:
                    insert_kwargs["session"] = session
                await self.db.version_status_history.insert_one(**insert_kwargs)
            except Exception as e:
                logger.warning(f"记录状态流转历史失败（表可能不存在）: {str(e)}")
        
        try:
            # 使用MongoDB事务确保数据一致性（如果部署支持）
            async with await self.db.client.start_session() as session:
                try:
                    async with session.start_transaction():
                        await _apply_changes(session=session)
                except OperationFailure as oe:
                    if oe.code == 20:  # 非副本集环境不支持事务
                        logger.warning(
                            "MongoDB 环境不支持事务，降级为非事务执行版本状态流转: %s", str(oe)
                        )
                        await _apply_changes(session=None)
                    else:
                        raise
        
        except OperationFailure as oe:
            if oe.code == 20:
                # start_session 本身可能在 standalone 环境抛出异常，执行降级逻辑
                logger.warning(
                    "MongoDB standalone 环境无法开启会话，使用非事务执行版本状态流转: %s", str(oe)
                )
                await _apply_changes(session=None)
            else:
                logger.error(
                    f"执行版本状态流转失败: version_id={version_id}, "
                    f"{from_status} -> {to_status}, error={str(oe)}",
                    exc_info=True
                )
                raise
            
            return {
                "version_id": str(version_id),
                "from_status": from_status,
                "to_status": to_status,
                "transition_type": transition_type,
                "trigger_source": trigger_source or "system",
                "operator_id": str(operator_id) if operator_id else None,
                "reason": reason,
                "comment": comment,
                "success": True
            }
            
        except Exception as e:
            logger.error(
                f"执行版本状态流转失败: version_id={version_id}, "
                f"{from_status} -> {to_status}, error={str(e)}",
                exc_info=True
            )
            raise
    
    async def get_transition_readiness(
        self,
        version_id: ObjectId,
        target_status: Optional[str] = None
    ) -> Dict:
        """
        获取版本状态流转准备情况（还差什么条件）
        
        Args:
            version_id: 版本ID
            target_status: 目标状态（如果指定，只检查该状态的流转规则）
        
        Returns:
            {
                "current_status": "development",
                "readiness": [
                    {
                        "target_status": "testing",
                        "rule_name": "进入测试",
                        "is_ready": False,
                        "unmet_conditions": ["任务完成度需达到80%（当前：75.0%）"]
                    }
                ]
            }
        """
        version = await self.db.versions.find_one({"_id": version_id})
        if not version:
            return {"error": "版本不存在"}
        
        current_status = version.get("status", "draft")
        
        # 获取流转规则
        if target_status:
            rule = VersionTransitionRules.get_rule(current_status, target_status)
            rules = [rule] if rule else []
        else:
            rules = VersionTransitionRules.get_rules_by_from_status(current_status)
        
        # 计算指标
        if current_status in ["draft", "planning"]:
            readiness_data = await self.completion_service.calculate_readiness_metrics(
                version_id, version
            )
            completion_data = {}
        else:
            completion_data = await self.completion_service.calculate_completion_rate(version_id)
            readiness_data = {}
        
        # 检查每个规则的条件
        readiness_list = []
        for rule in rules:
            is_met, unmet_conditions = await VersionTransitionRules.check_rule_conditions(
                rule, completion_data, readiness_data, version, self.db
            )
            
            readiness_list.append({
                "target_status": rule.to_status,
                "rule_name": rule.name,
                "is_ready": is_met,
                "unmet_conditions": unmet_conditions,
                "auto_trigger": rule.auto_trigger,
                "require_approval": rule.require_approval
            })
        
        return {
            "current_status": current_status,
            "completion_data": completion_data or readiness_data,
            "readiness": readiness_list
        }

